/***************** Modification History ***********************************
   @doc
   @module Pinpad.c - Basic PinPad functionality |
   @end
   
$Log: /SoftPay/SPK2SIM/Source/PINPad/pinpad.c $ 
**************************************************************************

   Copyright (C) 1999 by VeriFone, Inc.

   All rights reserved.  No part of this software may be reproduced,
   transmitted, transcribed, stored in a retrieval system, or translated
   into any language or computer language, in any form or by any means,
   electronic, mechanical, magnetic, optical, chemical, manual or otherwise,
   without the prior written permission of VeriFone, Inc.

---------------------------------------------------------------------------*/
#ifdef IMAM_LOG
#ifndef LOGSYS_FLAG
#define LOGSYS_FLAG
#endif
#endif

#include <project.h>
#ifdef PINPAD_DEFINED

#define VSPINPAD_C

#include <aclconio.h>
#include <errno.h>
#include <txoinc.h>
#include <stdio.h>
#include <ascii.h>
#include <stdlib.h>
#include <acldev.h>
#include <string.h>
#include <aclstr.h>
#include <portdef.h>
#include <aclascii.h>
#include <applidl.h>
#include <ctype.h>
#include <actutil.h>
#include <svc.h>

#ifdef DEBUG_VSPINPAD
#define DEBUG_95
#endif


#include <define.h>
#include <transact.h>
#include <pinpad.h>
#include <pinmsg.h>
#include <gds.h>
#include <cdt.h>
#include <cst.h>
#include <dct.h>
#include <hdt.h>
#include <tct.h>
#include <pct.h>
#include <amount.h>
#include <entry.h>
#include <init.h>
#include <msg.h>
#include <msgfuncs.h>
#include <spamsg.h>
#include <pp1000.h>
#include <pp101.h>
#include <print.h>
#include <spdebug.h>
#include <tran.h>
#include <date.h>
#include <format.h>
#include <ui.h>
#include <scalls.h>
#include <stats.h>
#include <table.h>
#include <funcids.h>
#include <rs232.h>
#include <passwd.h>
#include <validt.h>
#include <scproto.h>
#include <codesec.h>
#include <fleet.h>
#include <handheld.h>
#include "..\..\hostsrc\imamsrc\ImamComPort.h"

VS_BOOL gfPPadPresent = VS_TRUE;   /* Global flag to determine if PinPad is present */
PINPAD_OBJECT obPinPad;
extern char szImamEnterPinLabel[22];
extern char szImamPAN[PAN_SIZE+1];
extern int inImamLineNumber;
extern int hIPPComPort;

FUNCTION_TABLE srPinPadFuncs[] = {
    {inGetPinAccMac,            GET_PIN_ACC_MAC},
    #ifdef HAND_HELD_DEFINED
    {inHHGetPinAccMac,          HH_GET_PIN_ACC_MAC},
    #endif /* HAND_HELD_DEFINED*/
    {inPinPadTypeVal,           PINPAD_TYPE_VAL},
    {inPinPadBaudVal,           PINPAD_BAUD_VAL},
    {inPinPadFmtVal,            PINPAD_FMT_VAL},
    {inDebitBalanceDisplay,     DISPLAY_BAL_PINPAD},
    {inDebitReset,              PINPAD_RESET},
    {inSetupPinPad,             SETUP_PINPAD}, /* vsk -- added custom initialisation of Pinpad */
    {0,                         END_OF_FUNC_TABLE},

};


/********************************************************************************************* 
* @func int | inAddPinPadFunctions | 
*       Adds PINPAD functions to the flexi record.
*
* @rdesc return values.
* @flag int    |  VS_ERR, VS_ESCAPE or VS_SUCCESS
* @end
**********************************************************************************************/
int inAddPinPadFunctions(void) {
    int inCount = 0;

    /* Add PinPad functions to the flexi record */
    do {
        if (inAddFunctionPointer(srPinPadFuncs[inCount].inFieldID, srPinPadFuncs[inCount].pinFunction) == VS_ERR)
            return (VS_ERR);
        inCount++;
    } while (srPinPadFuncs[inCount].inFieldID != END_OF_FUNC_TABLE);

    return(VS_SUCCESS);
}



/********************************************************************************************* 
* @func int | inInitializePinPad |
*
* This function uses the PinPad object function pointers to:
*   - Initialize the Pinpad
*   - Set up the PinPad idle prompt
*
* @parm void 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inInitializePinPad() {
    int inRetVal;

    inRetVal = obPinPad.inInitPinPad();
    if (inRetVal != VS_SUCCESS) {
        gfPPadPresent = VS_FALSE;
        //        vdDisplayMessageFromFile( PINPAD_ERR_MSG21, WARNING_MSG);
        INCREMENT_PINPAD_ERROR;

        /* 
         * Return SUCCESS even though no PinPad may be connected to the Terminal
         */
        return VS_SUCCESS;
    } else
        gfPPadPresent = VS_TRUE;

    inExecPinPadIdlePrompt();

    return (VS_SUCCESS);
}


/********************************************************************************************* 
* @func int | inSetupPinPad |
*
* This routine is called to Setup the PinPad at power-up and also when the
* PinPad Type is changed via Setup. The global flag gfPPadPresent is set
* accordingly.
*
* @parm int | inPinPadType | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @end
**********************************************************************************************/
int inSetupPinPad(int inPinPadType) {
    gfPPadPresent = VS_TRUE;    /* Default value */

    switch (inPinPadType) {
    case NO_PINPAD:
        gfPPadPresent = VS_FALSE;
        break;

    case PP101:
        /* fall-thru */
    case PP1000:
        /* fall-thru */
    case PP102:
        /* fall-thru */
    case PP201:
        /* fall-thru */
    case PP2000:
        inSetupPinPadInfo(inPinPadType);
        break;

    case IPP:
        /* Internal PinPad */
        inSetupIPPInfo(inPinPadType);
        break;

#ifdef PP501_ICPA 
    case PP501:
        /* PinPad 501 */
        inSetupPP501Info(inPinPadType);
        break;
#endif  /* --- */

#ifdef SC_DEFINED           
    case SC552:
        /* SC552 device */
        inSetupSC552Info(inPinPadType);
        break;

    case SC455:
        /* SC455 device */
        gfPPadPresent = VS_FALSE;   // False for now till actual setup func is available
        break;
#endif  /* --- */

    default:
        gfPPadPresent = VS_FALSE;   // Default is No Pinpad
        break;
    }
    return VS_SUCCESS;
}


/* 
 * Generic PinPad setup function for PP101, PP1000, PP102, PP201, PP2000
 */
int inSetupPinPadInfo(int inPinPadType) {
    /* Set up PinPad object fields */
    obPinPad.inHandle = -1;
    obPinPad.inType = inPinPadType;
    obPinPad.inTimeout = PPADTIMEOUT;
    obPinPad.inInitPinPad = inInitPinPad;
    obPinPad.inSetPinPadIdlePrompt = inSetPPIdlePrompt;
    obPinPad.inDisplayPinPadString = inDispPPStr;
    obPinPad.inGetPin = inGetPin;
    /* ---
       Do not prompt for Tip Amount on PinPad. If called, use IPP's version of 
       this function to prompt for Tip Amount on the terminal display.
    obPinPad.inGetTipAmount         = inGetTipAmt;
    --- */
    obPinPad.inGetTipAmount = inGetIPPTipAmt;
    obPinPad.inPPadConnectTest = inPPadConnectTest;
    obPinPad.vdSendAbortToPINPad = vdSendAbortToPINPad;

    return VS_SUCCESS;
}

/* 
 * PinPad setup function for IPP 
 */
int inSetupIPPInfo(int inPinPadType) {
    /* Set up PinPad object fields */
    obPinPad.inHandle = -1;
    obPinPad.inType = inPinPadType;
    obPinPad.inTimeout = PPADTIMEOUT;
    obPinPad.inInitPinPad = inInitPinPad;
    obPinPad.inSetPinPadIdlePrompt = inSetIPPIdlePrompt;
    obPinPad.inDisplayPinPadString = inDispIPPStr;
    obPinPad.inGetPin = inGetIPPPin;
    obPinPad.inGetTipAmount = inGetIPPTipAmt;
    obPinPad.inPPadConnectTest = inPPadConnectTest;
    obPinPad.vdSendAbortToPINPad = vdSendAbortToPINPad;
    return VS_SUCCESS;
}


/********************************************************************************************* 
* @func int | inExecPinPadIdlePrompt |
*
* This routine is called to send the PinPad Idle Prompt to the PinPad.
* The global flag gfPPadPresent is reset if we don't get a good 
* response from the PinPad in the allowed time.
*
* @parm VOID
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @end
**********************************************************************************************/
int inExecPinPadIdlePrompt() {
    int inPPRetries = 5;
    unsigned long   ulPPTimeOut;

    ulPPTimeOut = set_itimeout(NO_CLOCK_HANDLE obPinPad.inTimeout, TM_SECONDS);
    while (CHECK_TIMEOUT(ulPPTimeOut)) {
        /* Call actual PinPad idle prompt function via function pointer */
        if (obPinPad.inSetPinPadIdlePrompt() == VS_SUCCESS) {
            gfPPadPresent = VS_TRUE;
            break;
        }

        /* Break out if we've reached the retry limit or have timed out */
        if (!(--inPPRetries) || !(CHECK_TIMEOUT(ulPPTimeOut))) {
            vdDisplayMessageFromFile(PINPAD_ERR_MSG21, WARNING_MSG);
            INCREMENT_PINPAD_ERROR;
            gfPPadPresent = VS_FALSE;
            break;
        }

        vdDelay(1000);  /* Wait for 1 second and try again */
    }
    return VS_SUCCESS;
}


/********************************************************************************************* 
* @func int | inInitPinPad |
*
* Common initialization routine for PinPad types PP101, PP1000, PP102,
* PP201, PP2000 and IPP.
* This routine will:
*   - open the PinPad port.
*   - initialize the PinPad port to the required Baud rate,
*     message data format and protocol.
*   - perform a standard PinPad connection test
*
* Notes: 
* 1. The baud and data format values are obtained from the TCT
*
* 2. The following initialization factors are assumed constant for 
*    all handled PinPads:
*    - Protocol = character mode.
*    - Packet start char is 0x02 (STX) and end character is 0x03 (ETX).
*
* @parm VOID
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS if the PinPad port is  opened successfully
* @flag int | VS_ERR if there is any error in the process
* @end
**********************************************************************************************/
int inInitPinPad() {
    int inPinPadType;
    struct Opn_Blk srPinPadInit;    /* Structure used for PinPad param init */
    char szPinPadDevice[10+1];
    /**/pdebug(("--inInitPinPad--"));/**/


    memset((char *) &srPinPadInit, 0x00, sizeof(srPinPadInit));
    srPinPadInit.rate = (char) inGetPinBarBaudRate();   /* Info found in TCT */
    srPinPadInit.format = (char) inGetPinBarDataFormat(); /* Info found in TCT */
    srPinPadInit.protocol = P_char_mode;
    srPinPadInit.parameter = 0;

	//inImamCloseComPort();
    /* Close the PinPad device if already open */
    if (obPinPad.inHandle != -1)
        if (close(obPinPad.inHandle) != 0) {
            vdDisplayMessageFromFile(PINPAD_ERR_MSG21, WARNING_MSG);
            return(VS_ERR);
        }

    /* Open the PinPad device */
    strcpy (szPinPadDevice, DEV_PINPAD);
/*
    if (inGetPINPadType()== IPP)
    {
#ifdef __arm
 strcpy ( szPinPadDevice, "/dev/com5");
#endif 
    }
*/
    obPinPad.inHandle = open(szPinPadDevice, O_RDWR);
	hIPPComPort = obPinPad.inHandle;

    if (obPinPad.inHandle < 0) {
        vdDisplayMessageFromFile(PINPAD_ERR_MSG21, WARNING_MSG);
        return(VS_ERR);
    }

    if (set_opn_blk(obPinPad.inHandle, &srPinPadInit)) {
        vdDisplayMessageFromFile(PINPAD_ERR_MSG21, WARNING_MSG);
        return(VS_ERR);         /* Error in setting the port's parameters */
    } else {
        if (inGetPINPadType() == IPP) {
            select_pinpad(PINPAD_INTERNAL);
            SVC_WAIT(50);
            IPP_power(PINPAD_ON);
            SVC_WAIT(300);  // Need this here per the Verix Func spec.
        } else {
            select_pinpad(PINPAD_EXTERNAL);
            SVC_WAIT(50);
            IPP_power(PINPAD_OFF);
            SVC_WAIT(300);  // Need this here per the Verix Func spec.
        }

        if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
            close(obPinPad.inHandle);
            vdDisplayMessageFromFile(PP_NOT_CONN_MSG15, WARNING_MSG);
            vdSGErrorMessage(PP_NOT_CONN_MSG15);
            gfPPadPresent = VS_FALSE;
            return(VS_ERR);
        }

        /* 
         * Send packet 15 (Set Key Management mode) for all PinPad types 
         * that support it, to set encryption mode to Master/Session or DUKPT
         */
        inPinPadType = inGetPINPadType();
        if ((inPinPadType == PP1000) || (inPinPadType == PP2000)) {
            if (inSetKeyManagement() != PP_CORRECT) {
                vdDisplayMessageFromFile(PINPAD_ERR_MSG21, WARNING_MSG);
                return(VS_ERR);
            }
        }
        return(VS_SUCCESS);     /* Success in setting the port's parameters */
    }
}


/********************************************************************************************* 
* @func int | inSendPinPadData |
*
* This routine handles the communication interface to the PinPad.
*
* @parm char *pchMsg - The data that is to be sent to the PinPad
* @parm int inTimeout - The timeout within which the response is expected
* @parm VS_BOOL fWaitForAck - Wait for ACK or not
*
* Assumptions:
* - If pchMsg[] is framed with SI and SO characters, no STX-ETX 
*   framing is performed.
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS if successful
* @flag int | VS_ERR for any error
* @end
**********************************************************************************************/
int inSendPinPadData(char* pchMsg,int inTimeout,VS_BOOL fWaitForAck) {
    int inRetval;
    VS_BOOL bAddFraming = TRUE;


    if (!gfPPadPresent)
        return(VS_ERR);

    /* Add framing and LRC to packet if using the STX-ETX protocol */
    if (pchMsg[0] != SI)
        bAddFraming = TRUE;
    else
        bAddFraming = FALSE;

    inRetval = inSendComPacket(obPinPad.inHandle, pchMsg, strlen(pchMsg), bAddFraming, inTimeout, fWaitForAck, PP_MAX_RETRIES);

    if (inRetval < 0) {
        INCREMENT_PINPAD_ERROR;
        vdSGErrorMessage(PINPAD_ERR_MSG21);
        return(VS_ERR);
    }
    return (VS_SUCCESS);
}


/********************************************************************************************* 
* @func int | inRecvPinPadData |
*
* This routine receives the data that is sent from the PinPad 
* in response to a inSendPinPadData() call.
*
* @parm char *pchRecvBuf - The receive data buffer
* @parm int inTimeout - The timeout within which the response is expected
* @parm int inMaxRecSize - Maximum size of data to receive
* @parm VS_BOOL fSendAck - Send ACK after getting response or not
*
* Notes            
* - Receive buffer using this should be no smaller than PINPAD_BUF_SIZE + 1
* - The framing characters received (STX/ETX/LRC) are retained in the 
*   receive data buffer (pchRecvBuf).
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | Number of bytes received (>0) if successful
* @flag int | VS_ESCAPE if CANCEL/CLEAR key is hit on Terminal/PinPad
* @flag int | VS_TIMEOUT if timed out waiting for response from PinPad
* @flag int | VS_ERR for any error
* @end
**********************************************************************************************/
int inRecvPinPadData(char* pchRecvBuf,int inTimeout,int inMaxRecSize,VS_BOOL fSendAck) {
    int inRetval;


    inRetval = inRecvCModePacket(obPinPad.inHandle, pchRecvBuf, inMaxRecSize, FALSE, inTimeout, fSendAck, PP_MAX_RETRIES);

    if (inRetval == ERR_COM_TIMEOUT) {
        vdSGErrorMessage(PINPAD_ERR_MSG21);
        INCREMENT_PINPAD_ERROR;
        return (VS_TIMEOUT);
    } else if (inRetval == VS_ESCAPE)         /* CANCEL key pressed */ {
        inResetPINPad();
        return (VS_ESCAPE);
    } else if (inRetval > 0) {
        if (!memcmp(&(pchRecvBuf[1]), "Z51?", 4)) {
            vdSGErrorMessage(PINPAD_ERR_MSG21);
            INCREMENT_PINPAD_ERROR;
            return (VS_TIMEOUT);
        }
        return inRetval;    /* Return # of bytes received */
    }
    return (VS_ERR);
}

int inImamRecvPinPadData(char* pchRecvBuf,int inTimeout,int inMaxRecSize,VS_BOOL fSendAck) {
    int inRetval;


    inRetval = inImamRecvCModePacket(obPinPad.inHandle, pchRecvBuf, inMaxRecSize, FALSE, inTimeout, fSendAck, PP_MAX_RETRIES);

    if (inRetval == ERR_COM_TIMEOUT) {
        vdSGErrorMessage(PINPAD_ERR_MSG21);
        INCREMENT_PINPAD_ERROR;
        return (VS_TIMEOUT);
    } else if (inRetval == VS_ESCAPE)         /* CANCEL key pressed */ {
        inResetPINPad();
        return (VS_ESCAPE);
    } else if (inRetval > 0) {
        if (!memcmp(&(pchRecvBuf[1]), "Z51?", 4)) {
            vdSGErrorMessage(PINPAD_ERR_MSG21);
            INCREMENT_PINPAD_ERROR;
            return (VS_TIMEOUT);
        }
        return inRetval;    /* Return # of bytes received */
    }
    return (VS_ERR);
}

/********************************************************************************************* 
* @func int | inPPDispBalance |
*
* This routine displays the balance amount on the PinPad for a 
* Balance Inquiry transaction
*
* @parm char *pszBalance - The balance amount to be displayed
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_TRUE
* @end
**********************************************************************************************/
int inPPDispBalance(char* pszBalance) {
    if (obPinPad.inDisplayPinPadString(CLR, pszBalance) != VS_SUCCESS) {
        vdSGErrorMessage(PINPAD_ERR_MSG21);
        INCREMENT_PINPAD_ERROR;
        return(VS_TRUE);
    }
    return(VS_TRUE);
}


/********************************************************************************************* 
* @func void | vdPPAdvTransFailed |
*
* This routine displays a message on the PinPad advising that the 
* transaction failed
*
* @parm void
* @end
**********************************************************************************************/
void vdPPAdvTransFailed() {
    char szDispMsg[MESSAGE_SIZE + 1];
    char szPPadMessage[MESSAGE_SIZE + 1];


    memset(szDispMsg, '\0', sizeof(szDispMsg));
    memset(szPPadMessage, '\0', sizeof(szPPadMessage));

    vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_TRANS_FAIL_MSG, szPPadMessage);
    vdDisplayErrorString(szPPadMessage);
    if (*szPPadMessage != NULL_CH)
        obPinPad.inDisplayPinPadString(CLR, szPPadMessage);
    else
        obPinPad.inDisplayPinPadString(CLR, szDispMsg);
}


/********************************************************************************************* 
* @func void | vdPPObtainCard |
*
* This routine displays a message on the PinPad advising Obtain Card
*
* @parm void
* @end
**********************************************************************************************/
void vdPPAdvObtainCard() {
    char szDispMsg[MESSAGE_SIZE + 1];

    vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, OBTAIN_CARD_MSG, szDispMsg);
    vdDisplayErrorString(szDispMsg);
    obPinPad.inDisplayPinPadString(CLR, szDispMsg);
}


/********************************************************************************************* 
* @func int | inSetPPIdlePrompt |
*
* This routine sets the idle prompt to be displayed on the PinPad by sending a Z8 packet.
* The string to be displayed on the PinPad is taken from the SPA message file.
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - if normal operation.
* @flag int | VS_ERR - if any error in Process.
* @end
**********************************************************************************************/
int inSetPPIdlePrompt() {
    char pchPPBuf[PINPAD_BUFFER_SIZE];
    char szApplName[TERM_ADDR_SIZE + 1];
    char szPINPadIdleMsg[MESSAGE_SIZE + 1];


    strcpy(szApplName, szGetRctHdr2());
    strcpy(pchPPBuf, "Z8");       /* Build the packet */
    vdGetMessageFromFile(PINPAD_IDLE_PROMPT_MSG, szPINPadIdleMsg);
    strcat(pchPPBuf, szPINPadIdleMsg);

    if (inSendPinPadData(pchPPBuf, 2, VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}


int inSetIPPIdlePrompt() {
    return VS_SUCCESS;  /* No PinPad idle prompt for IPP! */
}


/********************************************************************************************* 
* @func int | inResetPINPad |
*
* This routine will restore the PinPad to the idle state. This function
* can be called after a normal operation is complete or when the operation
* is aborted.
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - if normal operation.
* @flag int | VS_ERR - if any error in Process.
* @end
**********************************************************************************************/
int inResetPINPad() {
    char pchPinPadBuf[PINPAD_BUFFER_SIZE];


    if (inGetPINPadType() == IPP)
        vdFlushKeyboardBuffer();

    strcpy(pchPinPadBuf, "72");

    if (inSendPinPadData(pchPinPadBuf, 2, VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}


/********************************************************************************************* 
* @func int | inDispPPStr |
*
* This routine will display a string on the PinPad display.
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - if normal operation.
* @flag int | VS_ERR - if any error in Process.
* @end
**********************************************************************************************/
int inDispPPStr(char chClrDisplay,char* pszDispStr) {
    char szPinPadBuf[PINPAD_BUFFER_SIZE];


    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
        gfPPadPresent = VS_FALSE;
        return(VS_ERR);
    }

    memset(szPinPadBuf, 0, sizeof(szPinPadBuf));
    strcpy(szPinPadBuf, "Z2");
    szPinPadBuf[strlen(szPinPadBuf)] = chClrDisplay;
    strcat(szPinPadBuf, pszDispStr);

    if (inSendPinPadData(szPinPadBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);

    return(VS_SUCCESS);
}


/* 
 * For IPP, display string on Terminal display
 */
int inDispIPPStr(char chClrDisplay,char* pszDispStr) {

    if (chClrDisplay == CLR) {
		vdDisplayAt(1, 2, " ", CLR_EOL);  //
		vdDisplayAt(1, 3, " ", CLR_EOL);
		vdDisplayAt(1, 4, " ", CLR_EOL);
		vdDisplayAt(1, 5, " ", CLR_EOL);
		vdDisplayAt(1, 6, " ", CLR_EOL);
		vdDisplayAt(1, 7, " ", CLR_EOL);
        //clrscr();
	}

    vdDisplayAt(obDisp.inHomeCol, obDisp.inDetailLine, pszDispStr, CLR_EOL);
	pause(200);  //liem
    return(VS_SUCCESS);
}

#ifdef HAND_HELD_DEFINED
/********************************************************************************************* 
* @func int | inHHGetPinAccMac |
*
* This routine will prompt the user for the PIN and for the encrypted PIN block.
* 
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @flag int | PP_CORRECT
* @end
**********************************************************************************************/
int inHHGetPinAccMac(TRANSACTION_OBJECT* pobTran) {
    int inResult;
    if ((inResult = inGetPinAccMac(pobTran)) != VS_SUCCESS) {
        vdDisplayMessageFromFile(lnGGErrorMessage(), WARNING_MSG);
        vdSGErrorMessage(0L);
        vdScrollDataEntry(!obDisp.blNoScrollEntries);
        vdShowReturnTerminalPassword();
        //        vdShowReturnTerminal();
    }

    return (inResult);
}
#endif /*HAND_HELD_DEFINED*/

/********************************************************************************************* 
* @func int | inGetPinAccMac |
*
* This routine will prompt the user for the PIN and for the encrypted PIN block.
* 
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @flag int | PP_CORRECT
* @end
**********************************************************************************************/
int inGetPinAccMac(TRANSACTION_OBJECT* pobTran) {
    int inRetVal = 0;


	    if (!fGetPinpadRequired() && (!pobTran->fInteracDebit)) {
			LOG_PRINTFF((0x08L, "fGetPinpadRequired [FALSE] ==> NON DEBIT"));
	        return(VS_SUCCESS);
		} else {
			LOG_PRINTFF((0x08L, "fGetPinpadRequired [OK]"));
		}

#ifdef FLEET_DEFINED
	    if ((inGetType() == FLEET_CARD) && (fGetFleetPIN() != VS_TRUE))
	        return(VS_SUCCESS);
#endif


	    // We haven't done anything yet so don't read old Cancel keys
	    vdFlushKeyboardBuffer();

	    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
	        vdSGErrorMessage(PINPAD_ERR_MSG21);
	       INCREMENT_PINPAD_ERROR;
	        gfPPadPresent = VS_FALSE;
	        return(VS_ERR);
	    }

	   inRetVal = obPinPad.inGetPin(pobTran);
	    switch (inRetVal) {
	    case PP_SUCCESS:
	        /* No error...continue */
	        break;

	    case PP_TIMEOUT:
	        /* An error occurred */
	        vdSGErrorMessage(PIN_ENTRY_ERR_MSG);
	        return(VS_ERR);

	    case PP_CANCEL:
	        /* An error occurred */
	        vdSGErrorMessage(TXN_CANCELLED);
	        return(VS_ERR);

	    case PP_CORRECT:
	        /* Correct pressed: code to loop */
	        vdBeep();
	        vdSGErrorMessage(CUSTOMER_REQ_CORR_ERR_MSG);
	        return(PP_CORRECT);

	    case PP_BADACCTLEN:
	        /* Account Number too short */
	        vdSGErrorMessage(BAD_ACCT_LEN_ERR_MSG);
	        return(VS_ERR);

	    case PP_ERROR:
	        /* An error occurred */
	    default:
	        /* Unknown error occurred */
	        vdSGErrorMessage(PINPAD_ERR_MSG21);
	            INCREMENT_PINPAD_ERROR;
	        return(VS_ERR);
	    }

#ifdef MAC
	    if (inMakeMACField() != VS_SUCCESS)     /* Get the MAC now! */
	        return(VS_ERR);
#endif /* MAC */

	    if (inResetPINPad() != VS_SUCCESS)      /* Return PinPad to Idle */
	        return(VS_ERR);

	    /* Any keypresses occurring on the terminal during PPad processing are flushed */
	    vdFlushKeyboardBuffer();

    return(VS_SUCCESS);
}


/********************************************************************************************* 
* @func int | inPPadConnectTest |
*
* This routine performs a standard PinPad connection test
* 
* @parm void
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inPPadConnectTest(void) {
    char pchPINBuf[PINPAD_BUFFER_SIZE];


    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));

    if (inGetPINPadType() == IPP)
        vdFlushKeyboardBuffer();

    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "11");

    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, PPADTIMEOUT / 2, VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}


/********************************************************************************************* 
* @func int | inGetPin |
*
* This routine will form a Z62 packet (Accept and Encrypt PIN) alongwith 
* the Card Account # and working key (if Master-Session) and sends it to the PinPad.
* The PinPad encrypts the PIN block and sends the cipher-text PIN block to 
* the terminal.
* For Master-Session mode, packet 71 (Transfer PIN Block) contains the 
*     cipher-text PIN block 
* For DUKPT mode, packet 71 (Transfer PIN Block) contains the 
*     Key Serial Number (KSN) and cipher-text PIN block 
* 
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inGetPin(TRANSACTION_OBJECT* pobTran) /* vsk -- added custom initialisation of Pinpad -- commented static modifier*/ {
    char szDispOver[16 + 1],
    szDispStr1[16 + 1],
    szDispStr2[16 + 1];
    char /*szEncKey[16 + 1], */ szPAN[PAN_SIZE + 1],
    szPINBlock[PIN_SIZE + 1];
    char szMaxPIN[2 + 1],
    szMinPIN[2 + 1];
    char pchPINBuf[PINPAD_BUFFER_SIZE];
    char szKSN[KSN_SIZE + 1];
    int inSize,
    inCnt = 0;                      /* No of retries set to 0 */
    char* pszEncKey;


    memset(szKSN, '\0', sizeof(szKSN));
    if (inGetEncryptMethod() != DUKPT)
        if (inSelectMasterKey() != VS_SUCCESS)
            return(PP_ERROR);

    //    vdGetDCTPINKey(szEncKey);
    pszEncKey = szGetPINKey();
    strcpy(szPAN, pobTran->srBRec.szPAN);
    sprintf(szMinPIN, "%02d", inGetMinPINDigit());
    sprintf(szMaxPIN, "%02d", inGetMaxPINDigit());

    vdDisplayMessageFromFile(PINENTRY_MSG21, WARNING_MSG);

    /* Message 1 */
    if (inGGCode() != DEBIT_BAL_INQ) {
        sprintf(szDispStr1, SUBSTITUTE_LD, pobTran->srBKey.lnTotalOfTransactionAmount);
        vdFormatAmount(szDispStr1, VS_TRUE);
        /* Make sure the alphas (currency symbol) are upper case because */
        /* the pinpad doesn't display lower case */
        vdUpperCasePinMsg(szDispStr1);
    } else
        memset(szDispStr1, 0x00, sizeof(szDispStr1));

    /* Message 2 */
    vdGetMessageFromFile(ENT_PIN_MSG16, szDispStr2);

    /* Message 3 (displayed after PIN entry) */
    vdGetMessageFromFile(THANKS_MSG16, szDispOver);

    /* 
     * Build Z62 packet to send to PinPad
     */
    memset(pchPINBuf, 0, sizeof(pchPINBuf));
    strcpy(pchPINBuf, "Z62.");              /* Start of packet */
    strcat(pchPINBuf, szPAN);               /* Card Account Number */
    pchPINBuf[strlen(pchPINBuf)] = FS;      /* To separate the Account Number */
    if (inGetEncryptMethod() != DUKPT)
        strcat(pchPINBuf, pszEncKey);         /* Append Working Key for Master-Session */
    strcat(pchPINBuf, szMinPIN);            /* Minimum PIN length */
    strcat(pchPINBuf, szMaxPIN);            /* Maximum PIN length */
    pchPINBuf[strlen(pchPINBuf)] = 'N';     /* Null PIN allowed flag; 'N' = No null PIN */
    strcat(pchPINBuf, szDispStr1);          /* Message 1 */
    pchPINBuf[strlen(pchPINBuf)] = FS;
    strcat(pchPINBuf, szDispStr2);          /* Message 2 */
    pchPINBuf[strlen(pchPINBuf)] = FS;
    strcat(pchPINBuf, szDispOver);          /* Message 3 (displayed after PIN entry) */

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(PP_ERROR);       /* Exit if inSendPinPadData fails */

    inSize = inRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);

    if (inSize == VS_ESCAPE)    /* Aborting from terminal, via Clear key */
        return(PP_CANCEL);

    if ((inSize <= 0) || (inSize == VS_TIMEOUT)) {
        if (inResetPINPad() != VS_SUCCESS)
            return(PP_ERROR);
        return(PP_TIMEOUT);             /* Nothing Received */
    }

    if (inGetEncryptMethod() != DUKPT)
        if ((inSize != PINPAD_PIN_RESP_LEN) && (pchPINBuf[0] != EOT))
            return(PP_TIMEOUT);

    if (pchPINBuf[0] == EOT)            /* CANCEL to act as Correction Key */
        return(PP_CANCEL);

    if (inGetEncryptMethod() != DUKPT) {
        strlcpy(szPINBlock, &(pchPINBuf[9]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
    } else    /* => DUKPT encryption */ {
        /*
        pdebug(("PB  %02X%02X%02X%02X%",
                pchPINBuf[4],pchPINBuf[5],pchPINBuf[6],pchPINBuf[7]));
        pdebug(("    %02X%02X%02X%02X%",
                pchPINBuf[8],pchPINBuf[9],pchPINBuf[10],pchPINBuf[11]));
        pdebug(("    %02X%02X%02X%02X%",
                pchPINBuf[12],pchPINBuf[13],pchPINBuf[14],pchPINBuf[15]));
        pdebug(("    %02X%02X%02X%02X%",
                pchPINBuf[16],pchPINBuf[17],pchPINBuf[18],pchPINBuf[19]));
        pdebug(("    %02X%02X%02X%02X%",
                pchPINBuf[20],pchPINBuf[21],pchPINBuf[22],pchPINBuf[23]));*/

        /* The expected packet is <STX>710[KSN 16-20][PIN Block 16]<ETX> */
        while (pchPINBuf[inCnt] != ETX && inCnt < (int) strlen(pchPINBuf))
            inCnt++;
        strlcpy(szPINBlock, &(pchPINBuf[inCnt - PIN_BLOCK_SIZE]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */

        /*
        pdebug(("PIN %02X%02X%02X%02X%02X%02X%02X%02X",
                szPINBlock[0], szPINBlock[1], szPINBlock[2], szPINBlock[3]));
        pdebug(("    %02X%02X%02X%02X%02X%02X%02X%02X",
                szPINBlock[4], szPINBlock[5], szPINBlock[6], szPINBlock[7]));*/

        strlcpy(szKSN, &(pchPINBuf[4]), inCnt - 4 - PIN_BLOCK_SIZE);
        pad(szKSN, szKSN, 'F', KSN_SIZE - 4, RIGHT);

        /* 
        pdebug(("KSN %02X%02X%02X%02X%",
                szKSN[0],szKSN[1],szKSN[2],szKSN[3]));
        pdebug(("    %02X%02X%02X%02X%",
                szKSN[4],szKSN[5],szKSN[6],szKSN[7]));
        pdebug(("    %02X%02X%",
                szKSN[8],szKSN[9]));*/

        strlcpy(pobTran->szKSN, szKSN, KSN_SIZE);
    }

    if (szPINBlock[0] == '\0')                      /* If buffer is empty cancel operation */
        return (PP_CANCEL);

    strlcpy(pobTran->szPIN, szPINBlock, PIN_SIZE);  /* Set in the Transaction Object */

    return(PP_SUCCESS);
}


/********************************************************************************************* 
* @func int | inGetIPPPin |
*
* IPP version of GetPin functionality.
* Prompt user for PIN using standard UI API functions.
* Form a Z63 packet (Accept and Encrypt embedded PIN) and send the cleartext 
* PIN to the IPP, alongwith the Card Account # and Working Key (if Master-Session)
* or "DUKPT ENCRYPTION" if DUKPT.
* In response to the request for the PIN, the IPP encrypts the formatted clear-text 
* PIN block and sends the cipher-text PIN block to the master device (terminal).
* For Master-Session mode, packet 71 (Transfer PIN Block - MS) contains the 
*     cipher-text PIN block 
* For DUKPT mode, packet 73 (Transfer PIN Block - DUKPT) contains the 
*     Key Serial Number (KSN) and cipher-text PIN block 
* 
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS
* @flag int | VS_ERR
* @end
**********************************************************************************************/
int inGetIPPPin(TRANSACTION_OBJECT* pobTran) {
    char szPAN[PAN_SIZE + 1],
    szPINBlock[PIN_SIZE + 1];
    char szMaxPIN[2 + 1],
    szMinPIN[2 + 1];
    char pchPINBuf[PINPAD_BUFFER_SIZE];
    char szKSN[KSN_SIZE + 1];
    int inSize,
    inCnt = 0;                      /* No of retries set to 0 */
    char* pszEncKey;


    memset(szKSN, '\0', sizeof(szKSN));
    if (inGetEncryptMethod() != DUKPT)
        if (inSelectMasterKey() != VS_SUCCESS)
            return(PP_ERROR);

    pszEncKey = szGetPINKey();
    strcpy(szPAN, pobTran->srBRec.szPAN);
    sprintf(szMinPIN, "%02d", inGetMinPINDigit());
    sprintf(szMaxPIN, "%02d", inGetMaxPINDigit());

	LOG_PRINTFF((0x08L, "szPAN = [%s]", (char *)szPAN));
	LOG_PRINTFF((0x08L, "szWK  = [%s]", (char *)pszEncKey))
    /* 
     * Build Z63 packet to send to PinPad
     */
    memset(pchPINBuf, 0, sizeof(pchPINBuf));
    strcpy(pchPINBuf, "Z63.");              /* Start of packet */
	if(strlen(szImamPAN)) {
		strcat(pchPINBuf, szImamPAN);
		strcpy(szImamPAN, "");
	} else {
		strcat(pchPINBuf, szPAN);               /* Card Account Number */
	}
    pchPINBuf[strlen(pchPINBuf)] = FS;      /* To separate the Account Number */
    if (inGetEncryptMethod() != DUKPT)
        strcat(pchPINBuf, pszEncKey);         /* Append Working Key for Master-Session */
    else
        strcat(pchPINBuf, "DUKPT ENCRYPTION");
    strcat(pchPINBuf, szMinPIN);            /* Minimum PIN length */
    strcat(pchPINBuf, szMaxPIN);            /* Maximum PIN length */
    pchPINBuf[strlen(pchPINBuf)] = 'N';     /* Null PIN allowed flag; 'N' = No null PIN */
    pchPINBuf[strlen(pchPINBuf)] = '*';     /* Echo char */

    /* Any keypresses occurring on the terminal before PPad processing are flushed */
    vdFlushKeyboardBuffer();

    vdWarnBeep();

//    vdDisplayMessageFromFile(PINENTRY_MSG21, STATUS_MSG);
//    gotoxy(11, obDisp.inStatusLine);  // Set up so PIN entry will start here
	vdDisplayAt(1, inImamLineNumber, " ", CLR_EOL);  //
	if (strlen(szImamEnterPinLabel)){
		vdDisplayAt(1, inImamLineNumber-1, szImamEnterPinLabel, CLR_EOL);
		if (strlen(szImamEnterPinLabel)>13) vdScrollDisplay();
		strcpy(szImamEnterPinLabel, "");
	} else {
		vdCustDisplayPrompt (PINENTRY_MSG21, VS_TRUE);  
	}
	gotoxy(15, inImamLineNumber-1);               // to solve 6 digit pin bug

    set_font("");  // This is needed for the backspace to work, by using the default font.

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(PP_ERROR);       /* Exit if inSendPinPadData fails */

    inSize = inImamRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);

    if (inSize == VS_ESCAPE)    /* Aborting from terminal, via Clear key */
        return(PP_CANCEL);

    if ((inSize == 0) || (inSize == VS_TIMEOUT)) {
        if (inResetPINPad() != VS_SUCCESS)
            return(PP_ERROR);
        return(PP_TIMEOUT);             /* Nothing Received */
    }

    if (inGetEncryptMethod() != DUKPT)
        if ((inSize != PINPAD_PIN_RESP_LEN) && (pchPINBuf[0] != EOT)) {
            if (!memcmp(&(pchPINBuf[1]), "71", 2))
                vdDispPinPadPkt73Error(pchPINBuf[3]);
            return(PP_TIMEOUT);
        }

    if (pchPINBuf[0] == EOT)            /* CANCEL to act as Correction Key */
        return(PP_CANCEL);

    if (inGetEncryptMethod() != DUKPT) {
        strlcpy(szPINBlock, &(pchPINBuf[9]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
    } else    /* => DUKPT encryption */ {
        if ((!memcmp(&(pchPINBuf[1]), "73", 2)) && inSize == 6)
            vdDispPinPadPkt73Error(pchPINBuf[3]);

        /* The expected packet is <STX>710[KSN 16-20][PIN Block 16]<ETX> */
        while (pchPINBuf[inCnt] != ETX && inCnt < (int) strlen(pchPINBuf))
            inCnt++;
        strlcpy(szPINBlock, &(pchPINBuf[inCnt - PIN_BLOCK_SIZE]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
        //        strlcpy(szKSN, &(pchPINBuf[4]), inCnt-4-PIN_BLOCK_SIZE);
        strlcpy(szKSN, &(pchPINBuf[9]), inCnt - 9 - PIN_BLOCK_SIZE);
        pad(szKSN, szKSN, 'F', KSN_SIZE - 9, RIGHT);
        strlcpy(pobTran->szKSN, szKSN, KSN_SIZE);
    }

    if (szPINBlock[0] == '\0')                      /* If buffer is empty cancel operation */
        return (PP_CANCEL);

    strlcpy(pobTran->szPIN, szPINBlock, PIN_SIZE);  /* Set in the Transaction Object */

    return(PP_SUCCESS);
} /* end func inGetIPPPin() */



/*
** Display Packet 73 errors.
*/
void vdDispPinPadPkt73Error(char chError) {
    char szMessage[MESSAGE_SIZE + 1];

    switch (chError) {
    case '1':
        /* No key */
        vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_NO_KEY_ERR_MSG, szMessage);
        break;

    case '2':
        /* Account error */
        vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_ACCNUM_ERR_MSG, szMessage);
        break;

    case '3':
        /* PIN too long */
        vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_PIN_TOO_LONG_ERR_MSG, szMessage);
        break;

    case '4':
        /* PIN too short / non-decimal PIN digit in PIN */
        vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_PIN_TOO_SHORT_ERR_MSG, szMessage);
        break;

    case '6':
        /* PIN Pad has over 1 million transactions */
        vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, PP_OVER_1MILLION_TXNS_ERR_MSG, szMessage);
        break;

    default:
        /* Invalid error */
        return;
    }

    vdDisplayErrorString(szMessage);
    return;
}


/********************************************************************************************* 
* @func int | inGetTipAmt |
*
* This routine prompts the user to enter the Tip Amount on the PinPad.
* Upto 7 digits can be entered.
*
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - Tip Amount entered successfully
* @flag int | VS_ERR - Error: PinPad not connected
* @flag int | PP_ERROR - All other errors
* @flag int | PP_CANCEL - if CANCEL key was hit on terminal
* @flag int | PP_TIMEOUT - if nothing was entered on PinPad in the given time
* @end
**********************************************************************************************/
int inGetTipAmt(TRANSACTION_OBJECT* pobTran) {
    int inSize,
    inStrLen;
    char szAmt[AMT_SIZE + 1];
    char szBuff[PINPAD_BUFFER_SIZE];
    char szDispStr1[16 + 1],
    szDispStr2[16 + 1];
    char szTimeOut[10];


    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
        gfPPadPresent = VS_FALSE;
        return(VS_ERR);
    }

    vdGetMessageFromThisFile(PINPAD_MESSAGE_FILE, ENT_PIN_TIP_MSG, szDispStr1);

    sprintf(szDispStr2, SUBSTITUTE_LD, pobTran->srBKey.lnTotalOfTransactionAmount);
    vdFormatAmount(szDispStr2, VS_TRUE);
    /* Make sure the alphas (currency symbol) are upper case because */
    /* the pinpad doesn't display lower case */
    vdUpperCasePinMsg(szDispStr2);

    memset(szBuff, 0, sizeof(szBuff));

    strcpy(szBuff, "Z32");
    strcat(szBuff, szDispStr2);
    szBuff[strlen(szBuff)] = FS;
    strcat(szBuff, szDispStr1);

    if (inSendPinPadData(szBuff, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(PP_ERROR);           /* Exit if inSendPinPadData fails */

    memset(szBuff, 0, sizeof(szBuff));

    strcpy(szBuff, "Z501");         /* Start the packet buffer */
    int2str(szTimeOut, inGetPPTimeOut());
    pad(szTimeOut, szTimeOut, '0', 3, RIGHT);
    strcat(szBuff, szTimeOut);
    strcat(szBuff, "07");           /* Length of the packet buffer */

    if (inSendPinPadData(szBuff, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(PP_ERROR);           /* Exit if inSendPinPadData fails */

    inSize = inRecvPinPadData(szBuff, inGetPPTimeOut() + 2, sizeof(szBuff), VS_TRUE);

    if (inSize == VS_ESCAPE)        /* Aborting from terminal, via Clear key */
        return(PP_CANCEL);

    if (inSize == 0 || inSize == VS_TIMEOUT) {
        return(PP_TIMEOUT);         /* Nothing Received */
    }

    if (szBuff[0] == EOT)           /* CANCEL to act as Correction Key */
        return(PP_CANCEL);

    strcpy(szAmt, &szBuff[4]);
    inStrLen = strlen(szAmt);
    strncpy(szAmt, szAmt, (inStrLen - 1));

    if (szAmt[0] == '\0')           /* If buffer is empty cancel operation */
        return(PP_CANCEL);

    pobTran->srBRec.lnTipAmount = atol(szAmt);
    return(PP_SUCCESS);
}


/********************************************************************************************* 
* @func int | inGetIPPTipAmt |
*
* IPP version of GetTipAmt functionality.
* This routine prompts the user to enter the Tip Amount on the Terminal.
* Upto 7 digits can be entered.
*
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - Tip Amount entered successfully
* @flag int | VS_ESCAPE - CANCEL key pressed or timed out waiting for input
* @end
**********************************************************************************************/
int inGetIPPTipAmt(TRANSACTION_OBJECT* pobTran) {
    int inResult;
    char* szDisplaySymbol;
    char szAmount[AMT_SIZE + 1];
    char szDispStr[16 + 1];

    vdClearNonTitleLines();

    /* Display Txn Amount */
    sprintf(szDispStr, SUBSTITUTE_LD, pobTran->srBKey.lnTotalOfTransactionAmount);
    vdFormatAmount(szDispStr, VS_TRUE);
    /* Make sure the alphas (currency symbol) are upper case because */
    /* the pinpad doesn't display lower case */
    vdUpperCasePinMsg(szDispStr);

    vdDisplayAt(obDisp.inHomeCol, obDisp.inDetailLine, szDispStr, CLR_EOL);

    /* Display Tip Amount prompt */
    vdDispMsgAt(TIP_AMOUNT_MSG, obDisp.inHomeCol, obDisp.inInputLine, CLR_EOL);

    szDisplaySymbol = szGetCurSymbol();

    /* Prompt user to enter Tip Amount on terminal (max $99999.99) */
    if ((inResult = inGetAmount(szAmount, VS_TRUE, 0L, 9999999L, szDisplaySymbol)) != VS_SUCCESS)
        return(inResult);

    return VS_SUCCESS;
}


/********************************************************************************************* 
* @func void | vdSendAbortToPINPad |
*
* This routine send a Cancel Session Request packet (packet "72") to the PinPad
*
* @parm void
*
* @end
**********************************************************************************************/
void vdSendAbortToPINPad() {
    char szBuffer[PINPAD_BUF_SIZE + 1];


    if (gfPPadPresent) {
        if (obPinPad.inPPadConnectTest() == VS_SUCCESS) {
            strcpy(szBuffer, "72");
            inSendPinPadData(szBuffer, inGetPPTimeOut(), VS_TRUE);
        } else
            gfPPadPresent = VS_FALSE;
    }
}

/********************************************************************************************* 
* @func int | inGetPinTip |
*
* This routine calls PIN Tip entry routine
*
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | PP_SUCCESS - Tip Amount entered successfully
* @flag int | VS_ERR - Error: PinPad not connected
* @flag int | PP_ERROR - All other errors
* @flag int | PP_CANCEL - if CANCEL key was hit on terminal
* @flag int | PP_TIMEOUT - if nothing was entered on PinPad in the given time
* @end
**********************************************************************************************/
int inGetPinTip(TRANSACTION_OBJECT* pobTran) {
    char szDispOver[16 + 1];
    int inResult;


    if ((inResult = obPinPad.inGetTipAmount(pobTran)) == PP_SUCCESS) {
        vdGetMessageFromFile(THANKS_MSG16, szDispOver);
        if (obPinPad.inDisplayPinPadString(CLR, szDispOver) != VS_SUCCESS) {
            vdSGErrorMessage(PINPAD_ERR_MSG21);
            INCREMENT_PINPAD_ERROR;
            return(PP_ERROR);
        }
        vdDelay(2000);          /* Give Customer 2 seconds to view */
        return(PP_SUCCESS);
    }
    vdSGErrorMessage(PINPAD_ERR_MSG21);
    INCREMENT_PINPAD_ERROR;
    return(inResult);
}


/********************************************************************************************* 
* @func int | inSelectMasterKey |
*
* This routine selects the appropriate master key by sending a 
* "08" packet to the PinPad.
*
* @parm void
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - Master Key set successfully
* @flag int | VS_ERR - Error in setting Master Key
* @end
**********************************************************************************************/
int inSelectMasterKey() {
    char pchPINBuf[PINPAD_BUFFER_SIZE];


    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "08");
    pchPINBuf[strlen(pchPINBuf)] = chGetMasterKeyAddress();
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}

int inImamTransferMasterKey(char MKAddress, char *szMasterKey)
{
    int inRetVal = 0;
	int inSize = 0;
	char pchPINBuf[PINPAD_BUFFER_SIZE];

	LOG_PRINTFF((0x08L, "--inTransferMasterKey--"));
    vdFlushKeyboardBuffer();
    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
       vdSGErrorMessage(PINPAD_ERR_MSG21);
       INCREMENT_PINPAD_ERROR;
	   gfPPadPresent = VS_FALSE;
       return(VS_ERR);
    }

    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "02");
    //pchPINBuf[strlen(pchPINBuf)] = chGetMasterKeyAddress();
	pchPINBuf[strlen(pchPINBuf)] = MKAddress;
	strcat(pchPINBuf, szMasterKey);
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) == VS_SUCCESS) {
		memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
		inSize = inRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);
		if (inSize == VS_ESCAPE) {   // Aborting from terminal, via Clear key 
			LOG_PRINTFF((0x08L, "Transfer Master Key Canceled"));
		} else if ((inSize == 0) || (inSize == VS_TIMEOUT)) { // Nothing Received 
			LOG_PRINTFF((0x08L, "PINPad Timeout Error, size = 0"));
		} else {
			LOG_PRINTFF((0x08L, "PP Resp: (%d)[%s]", strlen(pchPINBuf), pchPINBuf));
			//LOG_PRINT_HEX((unsigned char *)pchPINBuf, strlen(pchPINBuf));
			strcpy(pchPINBuf, &pchPINBuf[4]);
			pchPINBuf[16]=0x00;
			if (strcmp(pchPINBuf, szMasterKey)) {
				LOG_PRINTFF((0x08L, "Error Master Key Echo"));
				inSize = 0;
			}
			inRecvCModePacket(obPinPad.inHandle, pchPINBuf, sizeof(pchPINBuf), FALSE, inGetPPTimeOut(), FALSE, PP_MAX_RETRIES);
		}
	}
	
    if (inResetPINPad() != VS_SUCCESS) {     // Return PinPad to Idle 
		LOG_PRINTFF((0x08L, "Error Reset PINPad"));
        return(VS_ERR);
	}
    vdFlushKeyboardBuffer();

	LOG_PRINTFF((0x08L, "--inTransferMasterKey--End--"));
	if (inSize<=0) return (VS_ERR);
	return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inGetPinEntry |
*
* This routine gets a PIN entered by the user on the Terminal 
* (if the terminal has an IPP -- Paprika-Plus/Cayenne-Plus)
*
* @parm void
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_SUCCESS - PIN entered successfully
* @flag int | VS_ERR - PIN entry failed
* @end
**********************************************************************************************/
int inGetPinEntry(long lnMessage,char* pszBuffer,int inMinChars,int inMaxChars) {
    int inResult;

    /** pdebug(("--inGetPinEntry--"));**/
    obDisp.inMinPWLength = inMinChars;
    inResult = inEnterWithMessage(lnMessage, SCROLL_DISPLAY_FALSE, pszBuffer, INPUT_ALNUMS_PWD, inMaxChars, inValidatePwdMin);
    return inResult;
}

int inDebitBalanceDisplay(TRANSACTION_OBJECT* pobTran) {
    if (inGGCode() == DEBIT_BAL_INQ)
        if (inDisplayBalanceOnPINPad(pobTran) != VS_TRUE)
            return(VS_ERR);
    return(VS_SUCCESS);
}

/********************************************************************************************* 
* @func int | inDisplayBalanceOnPINPad |
*
* Displays Balance on PINpad or Terminal
*
* @parm TRANSACTION_OBJECT * | pobTran | 
*
* @rdesc Returns the success/failure status of the operation.
* @flag int | VS_TRUE
* @flag int | VS_FALSE
* @end
**********************************************************************************************/
int inDisplayBalanceOnPINPad(TRANSACTION_OBJECT* pobTran) {
    char szBalance[AMT_SIZE + 1 + 1];                 /* Extra +1 for '.'   */
    char szDisplayBuffer[DISP_STR_LEN + 1];

    sprintf(szBalance, SUBSTITUTE_LD, pobTran->srBRec.lnBaseTransactionAmount);
    vdTrimLeadZeroes(szBalance);
    vdFormatAmount(szBalance, VS_TRUE);
    /* Make sure the alphas (currency symbol) are upper case because */
    /* the pinpad doesn't display lower case */
    vdUpperCasePinMsg(szBalance);

    if (inGetPINPadType() != NO_PINPAD && (!(inGetPINPadType() == PP501 || inGetPINPadType() == SC552))) {
        if (inPPDispBalance(szBalance) != VS_TRUE)
            return(VS_FALSE);
    } else {
        sprintf(szDisplayBuffer, "Balance Amount : %s", szBalance);
        vdDisplayStatusString(szDisplayBuffer);
    }

    return(VS_TRUE);
}

int inDebitReset(TRANSACTION_OBJECT* pobTran) {
    if (inGGCode() == DEBIT_BAL_INQ)
        if (fGetDebitFlag() == DEBIT)
            inResetPINPad();
    return(VS_SUCCESS);
}

int PINPAD_CODE_CHECK(char* a,char* b,short* c,char* d,unsigned char* e) {
    GET_VER(a, b, c, d, e);
    return 1;
}


void vdUpperCasePinMsg(char* pchString) {
    int inLen,
    inCount;
    inLen = strlen(pchString);
    for (inCount = 0; inCount < inLen; inCount++) {
        if (isalpha(pchString[inCount]))
            pchString[inCount] = toupper(pchString[inCount]);
    }
} /* end func vdUpperCasePinMsg() */



#undef VSPINPAD_C

#endif  /* PINPAD_DEFINED */

